package bittorrent;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Request {
    /* const */
        public static final int eventEmpty = 0;     /* request dilakukan secara periodik */
        public static final int eventStarted = 1;   /* request pertama dari client kepada tracker */
        public static final int eventStopped = 2;   /* dikirimkan dari client kepada tracker jika client diberhentikan secara sengaja */
        public static final int eventCompleted = 3; /* dikirimkan dari client kepada tracker ketika proses mengunduh sudah selesai dengan sempurna */
        public static final int trackerPort = 1234;
    
    /* atribut - atribut yang dimiliki oleh Request */
        private String info_hash;   /* nilai hash-ing menggunakan sha-1 terhadap nama file yang ingin diunduh */
        private int port;           /* nomor port dimana client listening */
        private int uploaded = 0;   /* jumlah byte yang telah diunggah oleh client khusus untuk file info_hash, dihitung semenjak client mengirimkan started event kepada tracker */
        private int downloaded = 0; /* jumlah byte yang telah diunduh oleh client khusus untuk file info_hash, dihitung semenjak client mengirimkan started event kepada tracker */
        private int left = 0;       /* jumlah byte yang masih harus diunduh oleh client khusus untuk file info_hash */
        private int event = eventEmpty;
    
    /* constructor */
        public Request (Torrent torrent) throws NoSuchAlgorithmException, UnsupportedEncodingException {
            this.info_hash = SHA1(torrent.getFileName());
            this.port = trackerPort;
            this.event = eventStarted;
        }
    
    /* setter */
        public void setUploaded (int uploaded) {
            /* I.S. sebarang */
            /* F.S. nilai uploaded menjadi sama dengan nilai yang dimasukkan dalam parameter */
            /* Proses : mengubah nilai uploaded menjadi terdefinisi */
            this.uploaded = uploaded;
        }
        public void setDownloaded (int downloaded) {
            /* I.S. sebarang */
            /* F.S. nilai downloaded menjadi sama dengan nilai yang dimasukkan dalam parameter */
            /* Proses : mengubah nilai downloaded menjadi terdefinisi */
            this.downloaded = downloaded;
        }
        public void setLeft (int left) {
            /* I.S. sebarang */
            /* F.S. nilai left menjadi sama dengan nilai yang dimasukkan dalam parameter */
            /* Proses : mengubah nilai left menjadi terdefinisi */
            this.left = left;
        }

    /* getter */
        public String getInfoHash () {
            /* mengembalikan nilai dari info_hash */
            return (info_hash);
        }
        public int getPort () {
            /* mengembalikan nilai dari port */
            return (port);
        }
        public int getUploaded () {
            /* mengembalikan nilai dari uploaded */
            return (uploaded);
        }
        public int getDownloaded () {
            /* mengembalikan nilai dari downloaded */
            return (downloaded);
        }
        public int getLeft () {
            /* mengembalikan nilai dari left */
            return (left);
        }
        public int getEvent () {
            /* mengembalikan nilai dari event */
            return (event);
        }
    
    /* method - method yang dimiliki oleh Request */
        public static String convertToHex (byte[] data) {
            StringBuilder strBuff = new StringBuilder();
            for (int i = 0; i < data.length; ++i) {
                int nibble = (data[i] >>> 4) & 0x0F;
                int twoHalfs = 0;
                do {
                    if ((0 <= nibble) && (nibble <= 9)) {
                        strBuff.append((char)('0' + nibble));
                    } else {
                        strBuff.append((char)('a' + (nibble - 10)));
                    }
                    nibble = data[i] & 0x0F;
                } while (twoHalfs++ < 1);
            }
            return (strBuff.toString());
        }
        public static String SHA1 (String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes("iso-8859-1"), 0, str.length());
            byte[] sha1hash = md.digest();
        
            return (convertToHex(sha1hash));
        }
        public static String toURLEncoded (String str) throws UnsupportedEncodingException {
            return (URLEncoder.encode(str, "UTF-8"));
        }
        public String encodeRequest () throws UnsupportedEncodingException {
            StringBuilder strBuff = new StringBuilder();
            strBuff.append("filename=");
            strBuff.append(this.getInfoHash());
            
            strBuff.append("&");

            strBuff.append("port=");
            strBuff.append(this.getPort());

            strBuff.append("&");

            strBuff.append("uploaded=");
            strBuff.append(this.getUploaded());

            strBuff.append("&");

            strBuff.append("downloaded=");
            strBuff.append(this.getDownloaded());

            strBuff.append("&");

            strBuff.append("left=");
            strBuff.append(this.getLeft());

            strBuff.append("&");

            strBuff.append("event=");
            strBuff.append(this.getEvent());
        
            return (toURLEncoded(strBuff.toString()));
        }
}
